﻿using Castle.Core.Logging;
using DotNetCore.CAP;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using MiniExcelLibs;
using MySqlX.XDevAPI.Common;
using NPOI.HPSF;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZhonTai.Admin.Core;
using ZhonTai.Admin.Core.SignalR;
using ZhonTai.Industry.Contracts.Communication;
using ZhonTai.Industry.Contracts.Core.Record;
using ZhonTai.Industry.Contracts.Model.Dic;
using ZhonTai.Industry.Contracts.Model.Entity;

namespace ZhonTai.Industry.Contracts.Interactive
{
    /// <summary>
    /// 故障监控
    /// </summary>
    public class AlarmMonitor : BaseMonitor
    {
        public DataShip _ship;
        public DB _plcDB;
        public DB _mesDB;

        private SiemensPlc _plc;

        //PLC数据块地址
        private string _plcAddress;

        //PLC数据块长度
        private ushort _length;

        // 报警状态跟踪数组（每个bit对应一个报警）
        private bool[] alarmStatus;

        // 报警开始时间记录
        private DateTime[] alarmStartTimes;

        // 报警配置映射表（bit位置到报警信息）
        private Dictionary<int, AlarmDefinition> alarmMapping;

        // 线程安全队列用于处理报警记录
        private ConcurrentQueue<AlarmMessage> alarmQueue;

        // 用于数据库写入的独立timer
        private Timer dbWriterTimer;

        private StateMonitor _stateMonitor;
        private byte[] _previousData;
        private readonly ICapPublisher _cap;
        private readonly ILogger<AlarmMonitor> _logger;
        private readonly IHubContext<MessageHub> _hub;

        public AlarmMonitor(
            ILogger<AlarmMonitor> logger,
            int initialInterval = 1000) : base(initialInterval)
        {
            _hub = AppInfo.GetRequiredService<IHubContext<MessageHub>>();
            _logger = logger;
            _cap = AppInfo.GetRequiredService<ICapPublisher>();
            // 初始化报警队列和数据库写入timer
            alarmQueue = new ConcurrentQueue<AlarmMessage>();
            dbWriterTimer = new Timer(StoreAlarmsToDB);
        }

        /// <summary>
        /// 监控设备状态
        /// </summary>
        public void StateRead()
        {
            Task.Run(() =>
            {
                _stateMonitor = new StateMonitor();
                _stateMonitor.Initialization(_plc, "DB3000.2", _ship.OPCode);
                _stateMonitor.Start();
            });
        }

        public override void Stop()
        {
            dbWriterTimer?.Dispose();
            _stateMonitor?.Stop();
            base.Stop();
        }

        public void Initialization(DataShip dataShip)
        {
            _plc = InstanceDic.PLC[dataShip.StationId];
            _plcDB = dataShip.PLCDB;
            _mesDB = dataShip.MESDB;
            _plcAddress = "DB" + _plcDB.DBAddress + ".0";
            _length = _plcDB.DBLength;
            _ship = dataShip;
            // 初始化报警状态跟踪数组
            int totalBits = _plcDB.DBLength * 8;
            alarmStatus = new bool[totalBits];
            alarmStartTimes = new DateTime[totalBits];
            StateRead();
            LoadAlarmMapping();
            dbWriterTimer.Change(5000, 8000);
        }
        protected override void Execute()
        {
            try
            {
                var result = _plc.Read(_plcAddress, _length);
                if (result.IsSuccess)
                {
                    ByteSlice(result.Content);
                }
            }
            catch
            {
            }
        }
        /// <summary>
        /// 数组切片解析
        /// </summary>
        private void ByteSlice(byte[] input)
        {
            // 快速比较字节变化
            for (int byteIndex = 0; byteIndex < input.Length; byteIndex++)
            {
                byte currentByte = input[byteIndex];
                byte previousByte = _previousData?[byteIndex] ?? 0;
                if (currentByte == previousByte) continue;
                ProcessChangedByte(byteIndex, currentByte, previousByte);
            }
            _previousData = input;
        }

        private void ProcessChangedByte(int byteIndex, byte currentByte, byte previousByte)
        {
            byte changedBits = (byte)(currentByte ^ previousByte);
            if (changedBits == 0) return;

            // 只处理变化的bit位
            for (int bitIndex = 0; bitIndex < 8; bitIndex++)
            {
                if ((changedBits & (1 << bitIndex)) == 0) continue;

                int globalBitIndex = byteIndex * 8 + bitIndex;
                bool currentState = (currentByte & (1 << bitIndex)) != 0;

                HandleAlarmStateChange(globalBitIndex, currentState);
            }
        }

        private void HandleAlarmStateChange(int bitIndex, bool currentState)
        {
            // 获取报警定义
            if (!alarmMapping.TryGetValue(bitIndex, out var alarmDef))
            {
                return;
            }

            // 状态变化处理
            if (currentState != alarmStatus[bitIndex])
            {
                alarmStatus[bitIndex] = currentState;

                if (currentState)
                {
                    // 报警触发
                    alarmStartTimes[bitIndex] = DateTime.Now;
                    _ = _hub.Clients.All.SendAsync(_ship.OPCode + "AlarmErr", alarmDef.Description);
                }
                else
                {
                    // 报警恢复
                    var record = new AlarmMessage(
                        _ship.StationId,
                        alarmDef.Code,
                        alarmStartTimes[bitIndex],
                        DateTime.Now,
                        alarmDef.Description
                    );
                    alarmQueue.Enqueue(record);
                }
            }
        }

        private void StoreAlarmsToDB(object state)
        {
            const int batchSize = 50;
            var batchRecords = new List<AlarmMessage>(batchSize);

            while (alarmQueue.TryDequeue(out var record))
            {
                batchRecords.Add(record);
                if (batchRecords.Count >= batchSize)
                {
                    BulkInsertAlarms(batchRecords);
                    batchRecords.Clear();
                }
            }

            if (batchRecords.Count > 0)
            {
                BulkInsertAlarms(batchRecords);
            }
        }

        private void BulkInsertAlarms(List<AlarmMessage> records)
        {
            _cap.Publish("AlarmMonitor", records);
        }

        private void LoadAlarmMapping()
        {
            var env = AppInfo.GetRequiredService<IWebHostEnvironment>();
            var path = Path.Combine(env.WebRootPath, "AlarmErr", _ship.OPCode + ".xlsx");
            var alarmList = MiniExcel.Query(path).ToList();
            alarmMapping = new Dictionary<int, AlarmDefinition>(alarmList.Count);
            for (int i = 0; i < alarmList.Count; i++)
            {
                var des = alarmList[i + 1].M;
                if (des == null) return;
                alarmMapping.Add(i, new AlarmDefinition("AL" + (i + 1), des));
            }
        }
    }
}